Skip to content

fix(release): develop to main#604

Merged
bedatty merged 12 commits into
mainfrom
develop
Jul 22, 2026
Merged

fix(release): develop to main#604
bedatty merged 12 commits into
mainfrom
develop

Conversation

@bedatty

@bedatty bedatty commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
Lerian

GitHub Actions Shared Workflows


Description

Type of Change

  • feat: New workflow or new input/output/step in an existing workflow
  • fix: Bug fix in a workflow (incorrect behavior, broken step, wrong condition)
  • perf: Performance improvement (e.g. caching, parallelism, reduced steps)
  • refactor: Internal restructuring with no behavior change
  • docs: Documentation only (README, docs/, inline comments)
  • ci: Changes to self-CI (workflows under .github/workflows/ that run on this repo)
  • chore: Dependency bumps, config updates, maintenance
  • test: Adding or updating tests
  • BREAKING CHANGE: Callers must update their configuration after this PR

Breaking Changes

None.

Testing

  • YAML syntax validated locally
  • Triggered a real workflow run on a caller repository using @this-branch or the beta tag
  • Verified all existing inputs still work with default values
  • Confirmed no secrets or tokens are printed in logs
  • Checked that unrelated workflows are not affected

Caller repo / workflow run:

Related Issues

Closes #

gandalf-at-lerian and others added 9 commits July 20, 2026 15:34
Move the post-release backmerge (backmerge_source -> backmerge_target)
out of the publish_release matrix job into a dedicated 'backmerge' job
that depends on generate_changelog.

Previously the backmerge ran inline in publish_release, which completes
before the separate generate_changelog job commits CHANGELOG.md to main.
As a result main->develop was backmerged without the changelog, leaving
develop missing it. The backmerge-sync composite fetches origin/<source>
fresh, so ordering the job after the changelog commit guarantees the
changelog is carried into the target branch.

Also wires the new job into the notify job's failed-job reporting.
When on_existing_tag: skip skips build/push because the tag already
exists, the cosign steps were also skipped since they depended on
steps.build-push.outputs.digest and should_build != 'false'. A
transient cosign/Rekor failure on an already-pushed tag then had no
retry path short of a full rebuild or a brand new release.

Add a 'Resolve digest for existing tag' step that resolves the
digest from the existing registry tag via docker buildx imagetools
inspect when the build was skipped, and gate the cosign steps on
enable_cosign_sign alone, feeding
steps.build-push.outputs.digest || steps.existing-digest.outputs.digest.

Closes #559
Address CodeRabbit finding on PR #603: when both DockerHub and GHCR
are enabled, the existing-tag digest resolution always picked
DockerHub (or GHCR alone) and reused that single digest for both
registries' refs. If a tag existed in only one registry, this could
construct a nonexistent ref for the other registry using the wrong
digest.

Resolve each enabled registry's digest independently and only emit a
ref for a registry when its own digest was actually found.
…t digests

Address CodeRabbit findings on PR #603:

- Resolve digest for existing tag: distinguish a genuine 'tag not
  found' from an inspect/lookup failure (transient network error,
  auth issue) by emitting a ::warning:: with the actual error in the
  latter case, instead of silently treating both as 'no digest'.
  Kept fail-open (skip that registry, don't abort the job) to match
  this file's existing convention for the same tradeoff in the
  pre-flight tag-existence check just above.
- Report cosign signing status: stop collapsing to a single DIGEST
  value that discarded one registry's digest when both were
  resolved; REFS already lists each registry's fully-qualified ref
  with its own digest, so the redundant/lossy single-digest line was
  removed instead of duplicating that same registry-qualified data.
…rding

Address CodeRabbit findings on PR #603:

- Resolve digest for existing tag: percent-encode the captured
  'docker buildx imagetools inspect' output (%, CR, LF) before
  embedding it in a ::warning:: line, so it can't corrupt or spoof a
  workflow command annotation.
- Report cosign signing status: cosign-sign signs refs one by one, so
  a failure partway through the list doesn't mean every ref is
  unsigned. Reworded the summary to reflect that signing didn't
  complete for every ref instead of asserting all refs are unsigned.
@bedatty
bedatty requested a review from a team as a code owner July 22, 2026 14:37
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added cosign signing retries for already-pushed images/tags without rebuilding.
    • Digest resolution is handled per registry to support skip-build signing.
    • Post-release backmerge now runs after changelog generation to include changelog commits.
  • Bug Fixes
    • Cosign status reporting now reflects incomplete signing when only some refs can be resolved/signed.
    • Release notifications now surface backmerge failures more clearly.
  • Documentation
    • Updated build workflow guidance for skip-build behavior and signing retries.

Walkthrough

The build workflow retries cosign signing for existing tags by resolving registry digests. The release workflow moves post-release backmerge after changelog generation and reports backmerge failures through notifications.

Changes

Build signing recovery

Layer / File(s) Summary
Existing digest resolution
.github/workflows/build.yml, docs/build-workflow.md
Skipped builds inspect enabled registries for digests, expose lookup errors, and document signing retries for existing tags.
Cosign fallback and reporting
.github/workflows/build.yml
Cosign references use build or registry-resolved digests, signing runs when enabled, and status reporting reflects incomplete per-registry results.

Release backmerge sequencing

Layer / File(s) Summary
Post-release backmerge job
.github/workflows/release.yml
Post-release backmerge runs in a dedicated job after changelog generation with publication, branch, and prerequisite-result gates.
Backmerge failure notification
.github/workflows/release.yml
The notify job waits for backmerge and includes backmerge failures in Slack messages.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: build, security, changelog

Suggested reviewers: gandalf-at-lerian

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The template is mostly unfilled: it lacks a real summary, affected workflows, behavior changes, testing details, and related issue link. Add a concrete Description, list the changed workflows and behavior, fill in testing evidence, and replace the placeholder issue reference.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the release/backmerge aspect of the PR, though it does not mention the build and docs workflow changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
.github/workflows/build.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


Comment @coderabbitai help to get the list of available commands.

@lerian-studio lerian-studio added size/S PR changes 50–199 lines documentation Improvements or additions to documentation workflow Changes to one or more reusable workflow files labels Jul 22, 2026
@lerian-studio

lerian-studio commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Validation Summary

✅ PR Mergeable — no blocking failures

Check Status Blocking
Source Branch ✅ success yes
PR Title ✅ success yes
PR Description ✅ success yes
PR Size ✅ success no
Auto Labels ✅ success no
PR Metadata ✅ success no

🔍 View workflow run

@lerian-studio

lerian-studio commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🔍 Lint Analysis

Check Files Scanned Status
YAML Lint 2 file(s) ✅ success
Action Lint 2 file(s) ✅ success
Pinned Actions 2 file(s) ✅ success
Markdown Link Check 1 file(s) ✅ success
Spelling Check 3 file(s) ✅ success
Shell Check 2 file(s) ✅ success
README Check 2 file(s) ✅ success
Composite Schema no changes ⏭️ skipped
Deployment Matrix no changes ⏭️ skipped

🔍 View full scan logs

@lerian-studio

lerian-studio commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🛡️ CodeQL Analysis Results

Languages analyzed: actions

Found 1 issue(s): 1 Medium

Severity Rule File Message
🟡 Medium actions/untrusted-checkout/medium .github/workflows/build.yml:300 Potential unsafe checkout of untrusted pull request on non-privileged workflow.

🔍 View full scan logs | 🛡️ Security tab

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/build.yml (1)

531-561: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Sign step can run with empty image-refs when all digest resolution fails.

The sign step's guard was relaxed to just inputs.enable_cosign_sign (line 570), but steps.cosign-refs.outputs.refs can be empty precisely in the new skip-mode path this PR adds: if docker buildx imagetools inspect fails or returns no digest for every enabled registry, DOCKERHUB_FINAL/GHCR_FINAL are both empty, REFS stays "", and the sign step still invokes the cosign-sign composite. That composite documents image-refs as a required input with no default, per its README: .Manifest: provides the manifest or manifest list confirms the digest-extraction approach is sound, but the composite's contract states image-refs | Newline-separated fully qualified image references to sign (e.g., docker.io/org/app@sha256:abc...) | Yes | — — no defined behavior for an empty value. Before this change, the sign step only ran after a successful build, so refs was always non-empty; now the exact "recover from a transient failure" scenario this PR targets can also be the one where the sign step fires with nothing to sign, likely hard-failing the job (continue_gitops_on_signing_failure defaults false) even though the earlier per-registry ::warning:: messages already explained why no digest was found.

Guard the sign step against an empty refs list; the existing per-registry warnings already cover user-facing diagnostics for that case.

🔧 Proposed fix
       - name: Sign container images with cosign
-        if: inputs.enable_cosign_sign
+        if: inputs.enable_cosign_sign && steps.cosign-refs.outputs.refs != ''
         id: cosign-sign

Also applies to: 569-578

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 531 - 561, Update the cosign sign
step guard near the cosign-refs output so it runs only when
inputs.enable_cosign_sign is enabled and steps.cosign-refs.outputs.refs is
non-empty. Preserve the existing signing behavior when valid image references
are produced, while skipping the composite action when digest resolution leaves
refs empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 507-529: Extract the duplicated registry digest inspection in the
DockerHub and GHCR sections into a shared helper that accepts the image
reference and output key, then invoke it for both registries. In that helper,
capture stdout separately from stderr so only valid JSON reaches jq; retain the
existing warnings for missing digests and inspection failures, using
escape_for_warning for failure details.

In @.github/workflows/release.yml:
- Around line 500-507: Add a successful publish_release result requirement to
the backmerge job’s if condition alongside the existing publish_release_status
check. Keep the current always(), input, branch, and downstream-job conditions
unchanged so backmerge only runs after the entire release matrix succeeds.
- Line 508: Update the reusable-workflow job’s runs-on setting to use the
mandated blacksmith-4vcpu-ubuntu-2404 runner instead of the inputs.runner_type
expression, while leaving the rest of the job unchanged.

---

Outside diff comments:
In @.github/workflows/build.yml:
- Around line 531-561: Update the cosign sign step guard near the cosign-refs
output so it runs only when inputs.enable_cosign_sign is enabled and
steps.cosign-refs.outputs.refs is non-empty. Preserve the existing signing
behavior when valid image references are produced, while skipping the composite
action when digest resolution leaves refs empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 491d194b-daf9-45b4-a037-83334ead5022

📥 Commits

Reviewing files that changed from the base of the PR and between 081670f and 18d0f46.

📒 Files selected for processing (3)
  • .github/workflows/build.yml
  • .github/workflows/release.yml
  • docs/build-workflow.md

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
Address CodeRabbit finding on PR #604: 'docker buildx imagetools
inspect ... 2>&1' merged stderr into the same variable later fed to
jq on the success path. Any stderr chatter on an otherwise-successful
call (deprecation notice, credential-helper output) would corrupt the
JSON and produce a false 'no digest' warning.

Extracted the duplicated DockerHub/GHCR inspect logic into a
resolve_digest() helper that captures stdout and stderr separately
(stderr to a temp file, consumed only for the warning message on
failure), so a successful call is never at risk of stderr noise
breaking the digest parse.
@bedatty
bedatty temporarily deployed to create_release July 22, 2026 15:09 — with GitHub Actions Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 503-520: Update resolve_digest and its callers to propagate a
distinct lookup-failure status instead of treating failures as an empty digest.
Preserve empty-digest handling for genuinely absent tags, but ensure lines
554-563 detect any existing registry whose resolution failed, prevent partial
cosign success, and invoke the reporting/failure path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 62b03d2a-3e08-4dfc-b17f-e92887218e7d

📥 Commits

Reviewing files that changed from the base of the PR and between 18d0f46 and c073d03.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml
Address CodeRabbit finding on PR #604: when on_existing_tag: skip
retries signing across multiple registries, a genuine registry
lookup failure (as opposed to a confirmed-absent tag) collapsed to
an empty digest just like a normal 'not found', so that registry
was silently excluded from signing. If the OTHER enabled registry
resolved fine, cosign-sign succeeded for it, and the failure report
step (gated only on cosign-sign's own outcome) never ran -- leaving
one registry's already-published image unsigned with no visible
failure signal beyond a log warning.

resolve_digest() now also reports whether the lookup itself failed
(vs. the tag being genuinely absent). Build cosign image references
aggregates that into a has_lookup_error output, and Report cosign
signing status now fires on either cosign-sign failing OR a lookup
error, so a partially-unverified multi-registry signing run is
always visibly reported instead of looking like a clean success.
@bedatty
bedatty temporarily deployed to create_release July 22, 2026 16:29 — with GitHub Actions Inactive
@lerian-studio lerian-studio added size/M PR changes 200–499 lines and removed size/S PR changes 50–199 lines labels Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 609-611: Update the report step’s if condition using the visible
cosign-sign and cosign-refs checks to explicitly allow execution when the
workflow is not cancelled, such as by adding !cancelled(). Preserve the existing
signing-failure and lookup-error conditions so the warning runs after either
error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 773002de-e1e0-4b6c-b9a3-dd26ccac409a

📥 Commits

Reviewing files that changed from the base of the PR and between c073d03 and 07c4d0d.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml
Address CodeRabbit finding on PR #604: the 'Report cosign signing
status' step's if: had no explicit status-check function
(success()/always()/cancelled()/failure()), so GitHub Actions
implicitly ANDs success() onto it. When cosign-sign fails without
continue-on-error (the default, since continue_gitops_on_signing_failure
defaults to false), that implicit success() check is false, so this
report step -- whose entire purpose is to fire on that exact
failure -- was silently skipped in the default configuration.

Adding !cancelled() removes the implicit success() requirement while
still skipping on a cancelled run, letting the step run whenever
cosign-sign actually failed or a registry lookup error occurred.
@bedatty
bedatty temporarily deployed to create_release July 22, 2026 16:35 — with GitHub Actions Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/build.yml (2)

609-636: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the signing summary reflect the actual continuation state.

When continue_gitops_on_signing_failure is false, the report still runs but subsequent GitOps artifact steps are skipped. The summary nevertheless says upload was allowed to continue. It also claims the images are already present even when a registry lookup failed. Branch the summary on the continuation input and only claim presence for registries with verified refs.

Proposed fix
         env:
           REFS: ${{ steps.cosign-refs.outputs.refs }}
           APP_NAME: ${{ matrix.app.name }}
           SIGNING_FAILED: ${{ steps.cosign-sign.outcome == 'failure' }}
           HAS_LOOKUP_ERROR: ${{ steps.cosign-refs.outputs.has_lookup_error }}
+          CONTINUE_ON_SIGNING_FAILURE: ${{ inputs.continue_gitops_on_signing_failure || false }}

...
-            echo "GitOps artifact upload was allowed to continue (\`continue_gitops_on_signing_failure: true\`)."
-            echo "The image(s) above are immutable and already present in the registry, but signing did not complete for every one — some may already be signed, others may not be."
+            if [ "$CONTINUE_ON_SIGNING_FAILURE" == "true" ]; then
+              echo "GitOps artifact upload was allowed to continue (\`continue_gitops_on_signing_failure: true\`)."
+            else
+              echo "GitOps artifact upload was not allowed to continue; subsequent artifact steps may have been skipped."
+            fi
+            echo "For registries with verified refs, the image is immutable but signing did not complete for every one — some may already be signed, others may not be."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 609 - 636, Update the signing
failure summary block around SIGNING_FAILED and HAS_LOOKUP_ERROR to branch on
continue_gitops_on_signing_failure, stating that GitOps artifact upload was
skipped when false and allowed to continue only when true. Revise the
image-presence statement so it claims images are already present only for
registries with successfully verified refs, while explicitly excluding any
registry affected by a lookup error.

514-526: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Treat manifest parsing failures as lookup failures.

Because set -e is not enabled, a failed jq pipeline leaves digest empty but keeps failed=false. The workflow can then omit that registry and report successful signing for the remaining refs. Check the parser exit status and set failed=true when the inspect output is invalid.

Proposed fix
           if out=$(docker buildx imagetools inspect "$ref" --format '{{json .Manifest}}' 2>"$err_file"); then
-            digest=$(echo "$out" | jq -r '.digest // empty')
-            [ -z "$digest" ] && echo "::warning::docker buildx imagetools inspect for ${ref} returned no digest — cosign will skip this registry." >&2
+            if ! digest=$(printf '%s' "$out" | jq -r '.digest // empty'); then
+              failed="true"
+              echo "::warning::Failed to parse manifest output for ${ref} — cosign will skip this registry." >&2
+            elif [ -z "$digest" ]; then
+              echo "::warning::docker buildx imagetools inspect for ${ref} returned no digest — cosign will skip this registry." >&2
+            fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 514 - 526, Update resolve_digest so
jq parsing failures are detected and set failed=true, treating invalid inspect
output as a registry lookup failure. Check the parser exit status while
extracting digest, preserve the existing no-digest warning for successful
parsing with an empty digest, and route parsing errors through the existing
failure warning and cosign-skip behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/build.yml:
- Around line 609-636: Update the signing failure summary block around
SIGNING_FAILED and HAS_LOOKUP_ERROR to branch on
continue_gitops_on_signing_failure, stating that GitOps artifact upload was
skipped when false and allowed to continue only when true. Revise the
image-presence statement so it claims images are already present only for
registries with successfully verified refs, while explicitly excluding any
registry affected by a lookup error.
- Around line 514-526: Update resolve_digest so jq parsing failures are detected
and set failed=true, treating invalid inspect output as a registry lookup
failure. Check the parser exit status while extracting digest, preserve the
existing no-digest warning for successful parsing with an empty digest, and
route parsing errors through the existing failure warning and cosign-skip
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 25d48b75-c71f-4dea-a05d-41e7c3a47e32

📥 Commits

Reviewing files that changed from the base of the PR and between 07c4d0d and f77e0c0.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

@bedatty
bedatty merged commit 51b9c68 into main Jul 22, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/M PR changes 200–499 lines workflow Changes to one or more reusable workflow files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants